#include <stdio.h>
#include "cache.h"



/* @to point to the byte after the content */
int __send_data(int fid, int socket_id, off_t from, off_t to)
{
	int count = 4;
	ssize_t n;
	while (count > 0) {
		if (nonblocking_r(fid, FD_TIMEOUT) <= 0 || nonblocking_w(socket_id, FD_TIMEOUT) <= 0) {
			count --;
			continue;
		}
		n = sendfile(socket_id, fid, &from, to - from);
		if (n < 0)
			return 0;
		if (n == 0)
			count -- ;
		if (from >= to) {
			return 1;
		}
		last_send_time = time(0);
		sleep(2);
	}
	return 0;
}
void new_send_data(int fid, int socket_id, struct dl_task *dl_task){
	char http_head[1500] = {0};
	int http_head_i = 0;
	unsigned int len; /* point to first byte of real data */

	if(!dl_task->use206)
	{
		http_head_i += sprintf(http_head+http_head_i, "HTTP/1.1 200 Ok\r\n");
		http_head_i += sprintf(http_head+http_head_i, "Content-Length: %u\r\n", dl_task->total);
	} else
	{
		http_head_i += sprintf(http_head+http_head_i, "HTTP/1.1 206 Partial Content\r\n");
		http_head_i += sprintf(http_head+http_head_i, 
				"Content-Range: bytes %u-%u/%u\r\n", dl_task->from, dl_task->to-1, dl_task->total);
	}

	http_head_i += sprintf(http_head+http_head_i, "Path: %s\r\n", dl_task->url_info->file_path);
	http_head_i += sprintf(http_head+http_head_i, "Connection: close\r\n");

	if (send(socket_id,http_head, http_head_i,0) < 0) 
		return;
	len = sizeof(struct disk_fmt) + dl_task->disk->headlen;
	__send_data(fid, socket_id, sizeof(struct disk_fmt), len);
	__send_data(fid, socket_id, dl_task->from + len, dl_task->to + len);
}


int new_range_satisfied(struct dl_task *dl_task, struct disk_fmt *disk, struct stat *st)
{
	return dl_task->from + sizeof(struct disk_fmt) + disk->headlen < st->st_size;
}
void cache_response(int sock, int fd, struct url_info *url_info, struct disk_fmt *disk_fmt) 
{
	struct stat st;
	struct dl_task dl_task;

	dl_task.url_info = url_info;
	dl_task.disk = disk_fmt;

	if (fstat(fd, &st) < 0) {
		send_404(sock);
		goto out;
	}

	if (url_info->range) {
		if (get_range(url_info->range, &dl_task.from, &dl_task.to, disk_fmt->filelen) < 0) {
			send_404(sock);
			goto out;
		}
		dl_task.total = disk_fmt->filelen;
		dl_task.use206 = 1;
	} else { 
		dl_task.from = 0;
		dl_task.to = disk_fmt->filelen;
		dl_task.total = disk_fmt->filelen;
		dl_task.use206 = 0;
	}

	/* 
	 * now we start to check if the request(dl_task) would be satisfied.
	 * but if the file has not beed finished and is not fresh, delete it
	 * and start to download, it is the download process's responsibility
	 * to fork a new process to feed the client request.
	 */
	if (st.st_size < sizeof(struct disk_fmt) + disk_fmt->headlen + disk_fmt->filelen &&
			!file_fresh(&st)) {
		close(fd);
		fd = -1;
		remove(url_info->file_path);
		download_data(url_info, sock, gconf);
	} else if (new_range_satisfied(&dl_task, disk_fmt, &st)) {
		new_send_data(fd, sock, &dl_task);
	} else {
		send_404(sock);
	}
out:
	if (fd > 0)
		close(fd);
}
